#region Imported Namespaces
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Data;
using System.Drawing;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.SearchContext;
using AlphaPicker = PHSRAG.WebControls.AlphaPicker;
using Annunciator = PHSRAG.WebControls.Annunciator;
using DataAccess = PHSRAG.Utility.DataAccess;
using Settings = PHSRAG.Utility.Settings;
using Pager = PHSRAG.WebControls.Pager;
using Policy = PHSRAG.Insight21.Policy;
#endregion

namespace PHSRAG.Insight21.ClinicalTrials.Controls
{
	public partial class PersonPicker : System.Web.UI.UserControl
	{

		#region Constants
		private const string ClientScriptKey = "clientScript_A0BB452C-E797-4d74-8853-C8A54627F8BF";
		private const string DataKey = "data_F83612A9-A16D-44ee-B5A4-C49AE60B1808";
		private const string FilteredDataKey = "filtered_1CC22E19-4B6D-41da-B346-C4EF225186BC";
		private const string JavascriptViewAllCallback = "ResetPickerState";
		private const string JavascriptWindowTitle = "SetWindowTitle";
		private const string PickerFilterColumn = "PIName";
		#endregion

		#region Instance Variables (protected)
		/// <summary>The AlphaPicker helps in narrowing down the list of displayed items in the datagrid.</summary>

		/// <summary>The annunciator is used to display warning and error messages.</summary>

		/// <summary>The data grid displays data associated with a pick type.</summary>

		/// <summary>The page is used to paginate through the data grid.</summary>

		/// <summary>The button which instigates a search (and subsquent filtering).</summary>

		/// <summary>This control is used both by the PI and Lab picker, and the label may be set as appropirate.</summary>

		/// <summary>The text to use (if any) as a filter while loading the datagrid.</summary>

		#endregion

		#region Private Instance Variables
		private enum pickerColumns
		{
			Id = 0,
			Name, 
			Username, 
			Organization
		}
		#endregion

		#region Private Properties
		/// <summary>
		/// Get/Set the data used to initialize the AlphaPicker and the data grid. So as to avoid multiple hits on the
		/// database, the retrieved data is cached under a picker-specific key.
		/// </summary>
		private DataTable FilteredData
		{
			get
			{
				DataTable filteredDataTable = Session[FilteredDataKey] as DataTable;
				return (filteredDataTable == null) ? UserPickerData : filteredDataTable;
			}
			set
			{
				Session[FilteredDataKey] = value;
			}
		}

		/// <summary>
		/// Get/Set the data used to initialize the AlphaPicker and the data grid. So as to avoid multiple hits on the
		/// database, the retrieved data is cached under a picker-specific key.
		/// </summary>
		private DataTable UserPickerData
		{
			get
			{
				DataTable userPickerDataTable = Session[DataKey] as DataTable;
				if (userPickerDataTable == null)
				{
					userPickerDataTable = new DataTable( "Users" );
					DataAccess.LoadDataTable( userPickerDataTable, DataAccess.ConnectionString, "GetInsightRegisteredUsers");
					Session[DataKey] = userPickerDataTable;
				}
				
				return userPickerDataTable;
			}
		}
		#endregion

		#region Pagination Event Handlers
		/// <summary>
		/// Handler for the FirstPage event raised by the Pager. Force the data grid to display the first page.
		/// </summary>
		/// <param name="sender">Page control</param>
		/// <param name="e">Arguments associated with the event</param>
		/// <remarks>
		/// If the data grid is already displaying the first page, no further action is taken.
		/// </remarks>
		private void OnFirstPage(object sender, System.Web.UI.WebControls.CommandEventArgs e)
		{
			if (dataGrid.CurrentPageIndex != 0)
			{
				dataGrid.CurrentPageIndex = 0;
				LoadDataGrid();
			}
		}

		/// <summary>
		/// Handler for the LastPage event raised by the Pager. Force the data grid to display the last page.
		/// </summary>
		/// <param name="sender">Page control</param>
		/// <param name="e">Arguments associated with the event</param>
		/// <remarks>
		/// If the data grid is already displaying the last page, no further action is taken.
		/// </remarks>
		private void OnLastPage(object sender, System.Web.UI.WebControls.CommandEventArgs e)
		{
			if (dataGrid.CurrentPageIndex != (pager.PageCount - 1))
			{
				dataGrid.CurrentPageIndex = pager.PageCount - 1;
				LoadDataGrid();
			}
		}

		/// <summary>
		/// Handler for the NextPage event raised by the Pager. Force the data grid to display the next page.
		/// </summary>
		/// <param name="sender">Page control</param>
		/// <param name="e">Arguments associated with the event</param>
		/// <remarks>
		/// If the data grid is already displaying the last page, no further action is taken.
		/// </remarks>
		private void OnNextPage(object sender, System.Web.UI.WebControls.CommandEventArgs e)
		{
			if (dataGrid.CurrentPageIndex < (pager.PageCount - 1))
			{
				dataGrid.CurrentPageIndex++;
				LoadDataGrid();
			}
		}

		/// <summary>
		/// Handler for the PreviousPage event raised by the Pager. Force the data grid to display the previous page.
		/// </summary>
		/// <param name="sender">Page control</param>
		/// <param name="e">Arguments associated with the event</param>
		/// <remarks>
		/// If the data grid is already displaying the first page, no further action is taken.
		/// </remarks>
		private void OnPreviousPage(object sender, System.Web.UI.WebControls.CommandEventArgs e)
		{
			if (dataGrid.CurrentPageIndex > 0)
			{
				dataGrid.CurrentPageIndex--;
				LoadDataGrid();
			}
		}
		#endregion

		#region Overrides
		/// <summary>
		/// Register clientside scripts.
		/// </summary>
		/// <param name="e">Argument associated with the event.</param>
		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);
			RegisterClientScripts();
		}
		#endregion

		#region Event Handlers
		/// <summary>
		/// Handler for the event raised by the AlphaPicker when the selection changes. The selection could either be an
		/// alphabet, or the "ViewAlL" option. The CommandName property of the event argument indicates which alphabet was
		/// selected, or an empty string if the ViewAll option was selected. Based on the choice, the data is filtered and
		/// displayed in the data grid.
		/// Contents of the editor control (within the placeholder) will be reset.
		/// </summary>
		/// <param name="sender">Source of the event</param>
		/// <param name="e">Argument associated with the event</param>
		private void OnAlphaChanged(object sender, CommandEventArgs e)
		{
			LoadFilteredData(e.CommandName);
		}

		/// <summary>
		/// Handler for the event raised by the DataGrid when a row is clicked upon.
		/// </summary>
		/// <param name="source">DataGrid control</param>
		/// <param name="e">Arguments associated with the event</param>
		/// <remarks>
		/// The item command is raised when the user clicks on the LastName column for a row. That column contains a
		/// LinkButton whose CommandName is set to "Select". Events raised for any other reason are ignored.
		/// </remarks>
		private void OnItemCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e)
		{
			if (e.CommandName == "Select")
			{
				Session.Remove(FilteredDataKey);

				// Generate client-side script to close the window within which this control is loaded. In addition, a
				// is made to a javascript functino on the opener page to display the choice made.

				if (!Page.ClientScript.IsClientScriptBlockRegistered(ClientScriptKey))
				{
					string jsFunctionName = Page.Request.QueryString["Call"];

					string script = string.Format(
						"<script language=\"javascript\">\n" +
						"window.opener.{2}('{0}',\"{1}\");\n" +
						"window.close();\n\n" +
						"</script>\n", e.Item.Cells[(int)pickerColumns.Id].Text,
						((LinkButton)e.Item.Cells[(int)pickerColumns.Name].Controls[0]).Text,
						jsFunctionName == null ? "OnFirstClick" : jsFunctionName);

					Page.ClientScript.RegisterClientScriptBlock(GetType( ), ClientScriptKey, script);
				}
				Session["newPIaccess"] = e.Item.Cells[(int)pickerColumns.Id].Text;
				Session["PIName"] = ((LinkButton)e.Item.Cells[(int)pickerColumns.Name].Controls[0]).Text;					
			}
		}

		protected void OnPageLoad(object sender, System.EventArgs e)
		{
			if (!IsPostBack)
			{
				alphaPicker.Reset();
				alphaPicker.DataSource = UserPickerData;
				alphaPicker.DataColumn = PickerFilterColumn;
				alphaPicker.JavascriptViewAllCallback = JavascriptViewAllCallback;
				searchLabel.Text = "Search Users";

				dataGrid.PageSize = Settings.GetKeyValue("DataGrid.ItemsPerPage", 10);
				LoadDataGrid();
			}
		}
		
		/// <summary>
		/// Handler for the Search button. Helps in filtering the data displayed in the data grid.
		/// </summary>
		/// <param name="sender">The control which raised the event</param>
		/// <param name="e">Argument associated with the event</param>
		/// <remarks>
		/// <p>There are two inputs to the search action:</p>
		/// <list type="bullet">
		/// <item><description>An alphabet from the AlphaPicker</description></item>
		/// <item><description>Free-form text typed in the search text box</description></item>
		/// </list>
		/// <p>If any text is explicitly typed in the text box, it will override any alphabet selection.</p>
		/// <p>A search always implies displaying the first page of the data grid.</p>
		/// </remarks>
		protected void OnSearch(object sender, System.EventArgs e)
		{
			string filter = searchText.Text.Trim();
			if (filter.Length == 0)
				filter = alphaPicker.Selection;
			else
				alphaPicker.Selection = filter.Substring(0, 1);

			LoadFilteredData(filter);
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Load the DataGrid with PI data. The name of the stored procedure to be used for the load is specified by
		/// the invoking entity via QueryString using the key "DataLoader".
		/// Initialize the Pager based on the volume of data retrieved from the database. The navigation links on the
		/// Pager are also set.
		/// </summary>
		/// <remarks>
		/// The data that is loaded into the data grid is filtered based upon the selection in the alpha picker.
		/// </remarks>
		private void LoadDataGrid()
		{
			DataTable userPickerData = FilteredData;
			pager.RecordCount = userPickerData.Rows.Count;

			int pageCount = (pager.RecordCount / dataGrid.PageSize) + (int)(((pager.RecordCount % dataGrid.PageSize) == 0) ? 0 : 1);
			pager.PageCount = pageCount;
			pager.CurrentPage = dataGrid.CurrentPageIndex + 1;	// Pager uses 1-based index.

			dataGrid.DataSource = userPickerData;
			dataGrid.DataBind( );

			alphaPicker.Visible = searchLabel.Visible = searchText.Visible = search.Visible = pager.Visible = (dataGrid.Items.Count > 0);

			if (pager.Visible)
			{
				int startIndex = dataGrid.CurrentPageIndex * dataGrid.PageSize;
				pager.FirstRecord = startIndex + 1;
				pager.LastRecord = startIndex + Math.Min(startIndex + dataGrid.PageSize, dataGrid.Items.Count);

				ManageNavigationLinks( );
			}
			else
			{
				annunciator.Title = "Data Load Warning:";
				annunciator.Message = "No Users data found.";
				annunciator.Visible = true;
				dataGrid.Visible = false;

				Controls.Add(new LiteralControl(
					"<input type=\"button\" class=\"Button\" value=\"Close Window\" onclick=\"window.close();return false;\">"));
			}
		}

		/// <summary>
		/// Apply the filter criteria to the picker data and load the data grid.
		/// </summary>
		/// <param name="filter">Criteria to filter the data on</param>
		private void LoadFilteredData(string filter)
		{
			DataTable userPickerData = UserPickerData;
			DataRow[] rows = userPickerData.Select(string.Format("{0} LIKE '{1}%'", PickerFilterColumn, filter));
			if (rows.Length > 0)
			{
				DataTable filteredData = userPickerData.Clone();
				foreach (DataRow row in rows)
					filteredData.ImportRow(row);
				FilteredData = filteredData;

				dataGrid.CurrentPageIndex = 0;
				LoadDataGrid();
				dataGrid.Visible = pager.Visible = true;
			}
			else
			{
				annunciator.Title = "Data Load Warning:";
				annunciator.Message = "No Users data found matching the search criteria.";
				annunciator.Visible = true;
				dataGrid.Visible = pager.Visible = false;
			}
		}

		/// <summary>
		/// Set the First/Last/Next/Previous page links on the Pager control to enabled/disabled based on which page is
		/// being displayed in the DataGrid.
		/// The First/Previous links are disabled if the first page is being displayed.
		/// The Last/Next links are disabled if the last page is being displayed.
		/// </summary>
		private void ManageNavigationLinks( )
		{
			pager.EnableFirstPage = pager.EnablePreviousPage = (dataGrid.CurrentPageIndex != 0);
			pager.EnableLastPage = pager.EnableNextPage = (dataGrid.CurrentPageIndex != (pager.PageCount - 1));
		}

		private void RegisterClientScripts()
		{
			if ( !Page.ClientScript.IsClientScriptBlockRegistered( JavascriptViewAllCallback ) )
			{
				string script = string.Format(
					"<script language=\"javascript\">\n" +
					"function {0}()\n" +
					"{{\n" +
					"\tvar textbox = document.getElementById('{1}');\n" +
					"\tif (textbox != null)\n" +
					"\t\ttextbox.value = '';\n" +
					"}}\n" +
					"</script>\n", JavascriptViewAllCallback, searchText.ClientID);

				Page.ClientScript.RegisterClientScriptBlock(GetType( ),  JavascriptViewAllCallback, script );
			}

			if (!Page.ClientScript.IsClientScriptBlockRegistered(JavascriptWindowTitle))
			{
				string script2 = string.Format(
					"<script language=\"javascript\">\n" +
					"\twindow.pageTitle.text = \"Users Search\";\n" +
					"</script>\n");

				Page.ClientScript.RegisterClientScriptBlock(GetType( ), JavascriptWindowTitle, script2);
			}
		}
		#endregion

		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);
		}
		
		/// <summary>
		///		Required method for Designer support - do not modify
		///		the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.alphaPicker.AlphaChanged += new CommandEventHandler(OnAlphaChanged);
			this.pager.FirstPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnFirstPage);
			this.pager.PreviousPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnPreviousPage);
			this.pager.NextPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnNextPage);
			this.pager.LastPage += new System.Web.UI.WebControls.CommandEventHandler(this.OnLastPage);
			this.dataGrid.ItemCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.OnItemCommand);
			this.Load += new System.EventHandler(this.OnPageLoad);
		}
		#endregion
	}
}
